package com.carsa.blackberry.util.ui.widget;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.component.BasicEditField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.SeparatorField;
import net.rim.device.api.ui.container.VerticalFieldManager;

import com.carsa.blackberry.ui.UIKeys;

/**
 * @author Nahuel Barrios.
 * @since 20/07/2010.
 * @version 1.0
 */
public class FormField extends VerticalFieldManager {

    public static final int STYLE_READ_ONLY    = 1;
    public static final int STYLE_EDITABLE     = 2;
    public static final int STYLE_FIELD_CUSTOM = 3;

    private Hashtable       _fields            = new Hashtable();
    private int             _columns;
    private int[]           _columnsWidth      = null;
    private int             _style;
    private boolean         _addSeparator      = true;
    private int             _maximumChars      = UIKeys.SIZE_DEFAULT_MAXIMUM_CHARACTERS_FOR_BASIC_EDIT_FIELD;

    /**
     * Coloca la primer linea separatoria, siempre y cuando el formulario este seteado de manera tal que el resto de las
     * filas tienen tambien esta linea separatoria
     */
    protected void putFirstSeparator() {
	if (_addSeparator)
	    this.add(new SeparatorField());
    }

    /**
     * Crea un nuevo objeto de tipo FormField listo para agregar campos. Por default se colocara una linea separatoria
     * entre "fila" y "fila". Ademas, por default la cantidad de columnas sera de 2, y como no se indica el ancho de las
     * mismas entonces seran del mayor ancho posible y de igual ancho cada.
     * 
     * @param style
     *            El estilo de la segunda columna del formulario, puede ser STYLE_READ_ONLY, STYLE_EDITABLE,
     *            STYLE_FIELD_CUSTOM. En caso de indicar un valor distinto a uno de estos, se creara el campo como
     *            STYLE_READ_ONLY.
     */
    public FormField(int style) {
	super();
	_style = style;
	_columns = 2;
	this.putFirstSeparator();
    }

    /**
     * Crea un nuevo objeto de tipo FormField listo para agregar campos. Por default se colocara una linea separatoria
     * entre "fila" y "fila".
     * 
     * @param style
     *            El estilo de la segunda columna del formulario, puede ser STYLE_READ_ONLY, STYLE_EDITABLE,
     *            STYLE_FIELD_CUSTOM. En caso de indicar un valor distinto a uno de estos, se creara el campo como
     *            STYLE_READ_ONLY.
     * @param columns
     *            La cantidad de columnas que tendra el formulario. Como no se indica el ancho de las mismas entonces
     *            seran del mayor ancho posible y de igual ancho cada.
     */
    public FormField(int style, int columns) {
	super();
	_style = style;
	_columns = columns;
	this.putFirstSeparator();
    }

    /**
     * Crea un nuevo objeto de tipo FormField listo para agregar campos. Por default se colocara una linea separatoria
     * entre "fila" y "fila".
     * 
     * @param style
     *            El estilo de la segunda columna del formulario, puede ser STYLE_READ_ONLY, STYLE_EDITABLE,
     *            STYLE_FIELD_CUSTOM. En caso de indicar un valor distinto a uno de estos, se creara el campo como
     *            STYLE_READ_ONLY.
     * @param columnsWidth
     *            Un array de ints conteniendo la medida de cada columna. La sumatoria de los elementos debe ser igual
     *            al maximo ancho disponible de pantalla. Para el BlackBerry 8310 es de 320px.
     */
    public FormField(int style, int[] columnsWidth) {
	super();
	_style = style;
	_columnsWidth = columnsWidth;
	_columns = _columnsWidth.length;
	this.putFirstSeparator();
    }

    /**
     * Crea un nuevo objeto de tipo FormField listo para agregar campos. Por default se colocara una linea separatoria
     * entre "fila" y "fila".
     * 
     * @param style
     *            El estilo de la segunda columna del formulario, puede ser STYLE_READ_ONLY, STYLE_EDITABLE,
     *            STYLE_FIELD_CUSTOM. En caso de indicar un valor distinto a uno de estos, se creara el campo como
     *            STYLE_READ_ONLY.
     * @param columnsWidth
     *            Un array de ints conteniendo la medida de cada columna. La sumatoria de los elementos debe ser igual
     *            al maximo ancho disponible de pantalla. Para el BlackBerry 8310 es de 320px.
     * @param addSeparator
     *            Indica si se debe agregar, o no, una linea separatoria debajo de cada "fila" del formulario.
     */
    public FormField(int style, int[] columnsWidth, boolean addSeparator) {
	super();
	_style = style;
	_columnsWidth = columnsWidth;
	_columns = _columnsWidth.length;
	_addSeparator = addSeparator;
	this.putFirstSeparator();
    }

    /**
     * Crea un nuevo objeto de tipo FormField listo para agregar campos. Por default se colocara una linea separatoria
     * entre "fila" y "fila".
     * 
     * @param style
     *            El estilo de la segunda columna del formulario, puede ser STYLE_READ_ONLY, STYLE_EDITABLE,
     *            STYLE_FIELD_CUSTOM. En caso de indicar un valor distinto a uno de estos, se creara el campo como
     *            STYLE_READ_ONLY.
     * @param columns
     *            La cantidad de columnas que tendra el formulario. Como no se indica el ancho de las mismas entonces
     *            seran del mayor ancho posible y de igual ancho cada.
     * @param addSeparator
     *            La cantidad de columnas que tendra el formulario.
     */
    public FormField(int style, int columns, boolean addSeparator) {
	super();
	_columns = columns;
	_addSeparator = addSeparator;
	_style = style;
	this.putFirstSeparator();
    }

    /**
     * Agrega una fila al formulario, con el estilo que ya tiene el formulario entero.
     * 
     * @param label
     *            El label a colocar.
     * @param value
     *            El value a colocar.
     * @return true cuando se agrego la fila correctamente. false cuando no.
     */
    public boolean addField(String label, String value, long focusable) {
	return this.addField(label, value, _style, _maximumChars, focusable);
    }

    /**
     * Agrega una fila al formulario.
     * 
     * @param label
     *            El label a colocar.
     * @param value
     *            El value a colocar.
     * @param maximumChars
     *            La maxima cantidad de caracteres permitidos para el campo. Es decir, se creara el campo como style
     *            STYLE_EDITABLE
     * @return true cuando se agrego la fila correctamente. false cuando no.
     */
    public boolean addField(String label, String value, int maximumChars, long focusable) {
	return this.addField(label, value, STYLE_EDITABLE, maximumChars, focusable);
    }

    /**
     * Agrega todos los elementos del par labels-values al formulario, con el estilo que ya tiene el formulario entero.
     * 
     * @param labels
     *            Un {@link Vector} con los labels a colocar.
     * @param values
     *            Un {@link Vector} con los valores a colocar.
     * @return true cuando se pudieron agregar todos los campos. false cuando no se pudo agregar alguno de los campos.
     */
    public boolean addField(Vector labels, Vector values) {
	return this.addField(labels, values, _style, _maximumChars);
    }

    /**
     * Agrega todos los elementos del par labels-values al formulario.
     * 
     * @param labels
     *            Un {@link Vector} con los labels a colocar.
     * @param values
     *            Un {@link Vector} con los valores a colocar.
     * @param maximumChars
     *            La maxima cantidad de caracteres permitidos para los campos editables (es decir, que tenga un style
     *            STYLE_EDITABLE) que se van a agregar
     * @return true cuando se pudieron agregar todos los campos. false cuando no se pudo agregar alguno de los campos.
     */
    public boolean addField(Vector labels, Vector values, int maximumChars, long focusable) {
	return this.addField(labels, values, STYLE_EDITABLE, maximumChars, focusable);
    }

    /**
     * Agrega todos los elementos del par labels-values al formulario.
     * 
     * @param labels
     *            Un {@link Vector} con los labels a colocar.
     * @param values
     *            Un {@link Vector} con los valores a colocar.
     * @param style
     *            El estilo de la segunda columna del formulario para este conjunto de campos que se van a agregar,
     *            puede ser STYLE_READ_ONLY, STYLE_EDITABLE, STYLE_FIELD_CUSTOM. En caso de indicar un valor distinto a
     *            uno de estos, se creara el campo como STYLE_READ_ONLY.
     * @param maximumChars
     *            La maxima cantidad de caracteres permitidos para los campos editables (es decir, que tenga un style
     *            STYLE_EDITABLE) que se van a agregar
     * @return true cuando se pudieron agregar todos los campos. false cuando no se pudo agregar alguno de los campos.
     */
    protected boolean addField(Vector labels, Vector values, int style, int maximumChars, long focusable) {
	boolean ret = true;

	Enumeration labelsElements = labels.elements();
	Enumeration valuesElements = values.elements();
	while (labelsElements.hasMoreElements() && valuesElements.hasMoreElements()) {
	    String aLabel = (String) labelsElements.nextElement();
	    String aValue = (String) valuesElements.nextElement();

	    if (aLabel != null && aValue != null)
		ret = this.addField(aLabel, aValue, style, maximumChars, focusable);
	    else
		ret = false;
	}

	return ret;
    }

    /**
     * Agrega una fila al formulario.
     * 
     * @param label
     *            El label a colocar.
     * @param value
     *            El value a colocar.
     * @param style
     *            El estilo de la segunda columna del formulario para este conjunto de campos que se van a agregar,
     *            puede ser STYLE_READ_ONLY, STYLE_EDITABLE, STYLE_FIELD_CUSTOM. En caso de indicar un valor distinto a
     *            uno de estos, se creara el campo como STYLE_READ_ONLY.
     * @param maximumChars
     *            La maxima cantidad de caracteres permitidos para los campos editables (es decir, que tenga un style
     *            STYLE_EDITABLE) que se van a agregar
     * @return true cuando se agrego la fila correctamente. false cuando no.
     */
    public boolean addField(String label, String value, int style, int maximumChars, long focusable) {
	GridFieldManager aGrid;

	if (_columnsWidth != null)
	    aGrid = new GridFieldManager(_columnsWidth, 0);
	else
	    aGrid = new GridFieldManager(_columns, 0);

	aGrid.add(new LabelField(label));

	Field ef_value = null;
	switch (style) {
	case STYLE_READ_ONLY:
	    ef_value = new LabelField(value, focusable);
	    break;
	case STYLE_EDITABLE:
	    ef_value = new BasicEditField("", value, maximumChars, style);
	    break;
	default:
	    ef_value = new LabelField(value);
	    break;
	}
	aGrid.add(ef_value);

	this.add(aGrid);
	if (_addSeparator)
	    this.add(new SeparatorField());

	_fields.put(label, value);
	return true;

    }

    /**
     * @return the _fields
     */
    public Hashtable get_fields() {
	return _fields;
    }

    /**
     * @return the _addSeparator
     */
    public boolean is_addSeparator() {
	return _addSeparator;
    }

    /**
     * @param addSeparator
     *            the _addSeparator to set
     */
    public void set_addSeparator(boolean addSeparator) {
	_addSeparator = addSeparator;
    }

    /**
     * @return the _columns
     */
    public int get_columns() {
	return _columns;
    }

}
